//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <mantle.h>

#define AS_ENTER()      m_asLock.Lock()
#define AS_EXIT(r)      do { m_asLock.Unlock(); return r; } while (0)

//
// User Memory Settings
// set by elastos.cfg
//
Int32 g_LowMemoryThreshold            = 1024;                     // 4MB
Int32 g_CriticallyLowMemoryThreshold  = 512;                      // 2MB
Int32 g_HeapGrow1stThreshold          = 256;                      // 1MB
Int32 g_HeapGrow2ndThreshold          = 128;                      // 512KB
Int32 g_RestoreHeapGrowThreshold      = 384;                      // 1.5MB

Int32 g_UserHeapGrowThreshold         = g_HeapGrow1stThreshold;
Int32 g_UserStackGrowThreshold        = 64;                       // 256KB

#define DEFAULT_SPACE_ALIGN ((size_t)64U * (size_t)1024U)
#define SPACE_ALIGN(S) \
      (((S) + (DEFAULT_SPACE_ALIGN)) & ~(DEFAULT_SPACE_ALIGN - 1))

AS::~AS()
{
    VSegment *pSeg;

    if (m_pHat) {
        assert(!m_asLock.IsLocked());
        //
        // AS has been initialized, dispose it's resources
        //

        // Detach and unmap common segments list.
        //
        while ((pSeg = (VSegment *)m_commList.m_pNext) != &m_commList) {
            pSeg->Detach();
            pSeg->Unmap();
            delete pSeg;
        }

        // Detach and unmap private segments list(include the heap segment).
        //
        while ((pSeg = (VSegment *)m_privList.m_pNext) != &m_privList) {
            pSeg->Detach();
            pSeg->Unmap();
            delete pSeg;
        }

        if (NULL == ::GetCurrentProcess()) {
            HAT::ActivateKHAT();
        }
        m_pHat->Dispose();
        delete m_pHat;
    }
}

ECode AS::Map(
    UInt32 uAddr,
    UInt32 uSize,
    UInt32 dwFlags,
    UInt32 dwProtect,
    VDataSource * pDataSource,
    UInt32 uOffset,
    UInt32 *puAddr)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg, *pNewSeg;
    ECode ec;

    assert(m_pHat && "AS has not been initialized");
    assert(dwFlags & (MemoryMap_Shared | MemoryMap_Private));
    assert(puAddr);

    if (!pDataSource && (dwFlags & MemoryMap_Shared)
        || !uSize) {
        return E_INVALID_ARGUMENT;
    }

    if (uSize > PRIVATE_SIZE) return E_NOT_ENOUGH_ADDRESS_SPACE;

    AS_ENTER();

    if (dwFlags & MemoryMap_Fixed) {
        //
        // Make sure range of the specified region is valid and not
        // overlapped with exist segments.
        //

        if (uAddr < COMMON_LIMIT) {
            if (uAddr < COMMON_BASE) {
                ec = E_INVALID_ARGUMENT;
                goto ErrorExit;
            }
            else if (uAddr + uSize > COMMON_LIMIT) {
                ec = E_NOT_ENOUGH_ADDRESS_SPACE;
                goto ErrorExit;
            }
            pCurrentList = &m_commList;
        }
        else {
            if (uAddr < PRIVATE_BASE || uAddr >= PRIVATE_LIMIT) {
                ec = E_INVALID_ARGUMENT;
                goto ErrorExit;
            }
            else if (uAddr + uSize > PRIVATE_LIMIT) {
                ec = E_NOT_ENOUGH_ADDRESS_SPACE;
                goto ErrorExit;
            }
            pCurrentList = &m_privList;
        }

        ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
            if (pSeg->m_uBase >= uAddr) {
                if (pSeg->m_uBase < uAddr + uSize) {
                    ec = E_ALREADY_EXIST;
                    goto ErrorExit;
                }
                break;
            }
        }
        if (pSeg->m_pPrev != pCurrentList) {
            if (((VSegment *)(pSeg->m_pPrev))->m_uBase
                + ((VSegment *)pSeg->m_pPrev)->m_uSize > uAddr) {
                ec = E_ALREADY_EXIST;
                goto ErrorExit;
            }
        }
    }
    else {
        uAddr = VIRTUAL_ALLOC_BASE;

        ForEachDLinkNode(VSegment *, pSeg, &m_privList) {
            if (VIRTUAL_ALLOC_LIMIT < pSeg->m_uBase) {
                break;
            }
            if (VIRTUAL_ALLOC_BASE <= pSeg->m_uBase) {
                if (pSeg->m_uBase - uAddr >= SPACE_ALIGN(uSize)) {
                    break;
                }
                uAddr = SPACE_ALIGN(pSeg->m_uBase + pSeg->m_uSize);
            }
        }

        if (VIRTUAL_ALLOC_LIMIT - uAddr < SPACE_ALIGN(uSize)) {
            ec = E_NOT_ENOUGH_ADDRESS_SPACE;
            goto ErrorExit;
        }
    }

    pNewSeg = new StdSegment(
            this,
            uAddr,
            uSize,
            dwFlags,
            dwProtect,
            pDataSource,
            uOffset);
    if (!pNewSeg) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }

    if (NOERROR != (ec = pNewSeg->InitMap())) {
        delete pNewSeg;
        goto ErrorExit;
    }

    pSeg->InsertPrev(pNewSeg);
    *puAddr = uAddr;

    AS_EXIT(NOERROR);

ErrorExit:
    AS_EXIT(ec);
}

ECode AS::AllocThreadStack(
    UInt32 *puStackBase)
{
    VSegment *pSeg, *pNewSeg;
    ECode ec;
    UInt32 uAddr;

    assert(m_pHat && "AS has not been initialized");
    assert(puStackBase);

    AS_ENTER();

    uAddr = THREAD_STACK_LIMIT;
    ForEachDLinkNodeReversely(VSegment *, pSeg, &m_privList) {
        if (THREAD_STACK_BASE >= pSeg->m_uBase + pSeg->m_uSize) {
            break;
        }
        if (uAddr - (pSeg->m_uBase + pSeg->m_uSize) >= USER_STACK_ALIGN) {
            break;
        }
        assert(USER_STACK_SIZE == pSeg->m_uSize);
        uAddr = pSeg->m_uBase + USER_STACK_SIZE - USER_STACK_ALIGN;
    }

    if (uAddr < USER_STACK_ALIGN + THREAD_STACK_BASE) {
        ec = E_NOT_ENOUGH_ADDRESS_SPACE;
        goto ErrorExit;
    }
    uAddr -= USER_STACK_SIZE;

    assert(0 == ((uAddr + USER_STACK_SIZE) & (USER_STACK_ALIGN - 1)));

    pNewSeg = new StdSegment(
            this,
            uAddr,
            USER_STACK_SIZE,
            MemoryMap_Private | MemoryMap_DownGrow,
            MemoryProtection_Read | MemoryProtection_Write,
            NULL,
            0);
    if (!pNewSeg) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }

    if (NOERROR != (ec = pNewSeg->InitMap())) {
        delete pNewSeg;
        goto ErrorExit;
    }

    //
    // Commit one physical page for user stack.
    //
    ec = pNewSeg->Hit(
            uAddr + USER_STACK_SIZE - PAGE_SIZE);
    if (FAILED(ec)) {
        delete pNewSeg;
        goto ErrorExit;
    }

    pSeg->InsertNext(pNewSeg);
    *puStackBase = uAddr;

    AS_EXIT(NOERROR);

ErrorExit:
    AS_EXIT(ec);
}

ECode AS::DecreaseThreadStack(
    UInt32 uStackBase)
{
    ECode ec;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, &m_privList) {
        if (uStackBase == pSeg->m_uBase) {
            ec = pSeg->Decrease(uStackBase + USER_STACK_SIZE - PAGE_SIZE);

            AS_EXIT(ec);
        }
    }

    AS_EXIT(E_DOES_NOT_EXIST);
}

ECode AS::Remap(
    UInt32 uVAddr,
    UInt32 uSize,
    UInt32 uPAddr,
    UInt32 dwFlags,
    UInt32 dwProtect,
    UInt32 *puAddr)
{
    VSegment *pSeg, *pNewSeg;
    ECode ec;

    assert(m_pHat && "AS has not been initialized");
    assert(dwFlags & (MemoryMap_Shared | MemoryMap_Private));
    assert(!((dwFlags & MemoryMap_Shared) && !(dwFlags & MemoryMap_Fixed)));
    assert(puAddr || (dwFlags & MemoryMap_Fixed));
    assert(0 < uSize);

    AS_ENTER();

    if (dwFlags & MemoryMap_Fixed) {
        //
        // Make sure range of the specified region is valid and not
        // overlapped with exist segments.
        //
        DLinkNode *pCurrentList;

        if (uVAddr < COMMON_LIMIT) {
            if (uVAddr < COMMON_BASE) {
                ec = E_INVALID_ARGUMENT;
                goto ErrorExit;
            }
            else if (uVAddr + uSize > COMMON_LIMIT) {
                ec = E_NOT_ENOUGH_ADDRESS_SPACE;
                goto ErrorExit;
            }
            pCurrentList = &m_commList;
        }
        else {
            if (uVAddr < VIRTUAL_ALLOC_BASE
                || uVAddr >= VIRTUAL_ALLOC_LIMIT) {
                ec = E_INVALID_ARGUMENT;
                goto ErrorExit;
            }

            if (uVAddr + uSize > VIRTUAL_ALLOC_LIMIT) {
                ec = E_NOT_ENOUGH_ADDRESS_SPACE;
                goto ErrorExit;
            }
            pCurrentList = &m_privList;
        }

        ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
            if (pSeg->m_uBase >= uVAddr) {
                if (pSeg->m_uBase < uVAddr + uSize) {
                    ec = E_ALREADY_EXIST;
                    goto ErrorExit;
                }
                break;
            }
        }
        if (pSeg->m_pPrev != pCurrentList) {
            if (((VSegment *)(pSeg->m_pPrev))->m_uBase
                + ((VSegment *)pSeg->m_pPrev)->m_uSize > uVAddr) {
                ec = E_ALREADY_EXIST;
                goto ErrorExit;
            }
        }
    }
    else {
        uVAddr = VIRTUAL_ALLOC_BASE;

        ForEachDLinkNode(VSegment *, pSeg, &m_privList) {
            if (VIRTUAL_ALLOC_LIMIT < pSeg->m_uBase) {
                break;
            }
            if (VIRTUAL_ALLOC_BASE <= pSeg->m_uBase) {
                if (pSeg->m_uBase - uVAddr >= SPACE_ALIGN(uSize)) {
                    break;
                }
                uVAddr = SPACE_ALIGN(pSeg->m_uBase + pSeg->m_uSize);
            }
        }

        if (VIRTUAL_ALLOC_LIMIT - uVAddr < SPACE_ALIGN(uSize)) {
            ec = E_NOT_ENOUGH_ADDRESS_SPACE;
            goto ErrorExit;
        }
    }

    pNewSeg = new StdSegment(
            this,
            uVAddr,
            uSize,
            dwFlags,
            dwProtect,
            NULL,
            0);
    if (!pNewSeg) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }

    if (FALSE == m_pHat->LoadMap(uVAddr, uVAddr + uSize,
            uPAddr, dwProtect, TRUE)) {
        ec = E_OUT_OF_MEMORY;
        delete pNewSeg;
        goto ErrorExit;
    }

    pSeg->InsertPrev(pNewSeg);
    if (puAddr) *puAddr = uVAddr;
    AS_EXIT(NOERROR);

ErrorExit:
    AS_EXIT(ec);
}

ECode AS::Query(
    UInt32 uAddr,
    UInt32 *puBaseAddr,
    MemorySize *pSize)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");
    assert(puBaseAddr || pSize);

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uAddr, pSeg->m_uBase, pSeg->m_uSize)) {
            if (puBaseAddr) *puBaseAddr = pSeg->m_uBase;
            if (pSize)     *pSize = pSeg->m_uSize;
            AS_EXIT(NOERROR);
        }
    }

    AS_EXIT(E_DOES_NOT_EXIST);
}

ECode AS::QueryPhysicalBlock(
    UInt32 uVAddr,
    UInt32 *puPAddr,
    MemorySize *pSize)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;
    ECode ec;

    AS_ENTER();

    assert(m_pHat && "AS has not been initialized");

    if (uVAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uVAddr, pSeg->m_uBase, pSeg->m_uSize)) {
            ec = pSeg->QueryPhysicalBlock(uVAddr, puPAddr, pSize);
            AS_EXIT(ec);
        }
    }

    AS_EXIT(E_DOES_NOT_EXIST);
}

ECode AS::Unmap(
    UInt32 uAddr,
    UInt32 uSize)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (pSeg->m_uBase == uAddr && pSeg->m_uSize == uSize) {
            pSeg->Detach();
            pSeg->Unmap();
            delete pSeg;

            AS_EXIT(NOERROR);
        }
    }

    AS_EXIT(E_INVALID_ARGUMENT);
}

ECode AS::SetProtect(
    UInt32 uAddr,
    UInt32 uSize,
    UInt32 dwProtect)
{
    ECode ec;
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (pSeg->m_uBase == uAddr && pSeg->m_uSize == uSize) {
            ec = pSeg->SetProtect(dwProtect);

            AS_EXIT(ec);
        }
    }

    AS_EXIT(E_INVALID_ARGUMENT);
}

ECode AS::CheckProtect(
    UInt32 uAddr,
    UInt32 protect,
    Boolean *pIsValid)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uAddr, pSeg->m_uBase, pSeg->m_uSize)) {
            *pIsValid = pSeg->CheckProtect(protect);
            AS_EXIT(NOERROR);
        }
    }

    AS_EXIT(E_ACCESS_DENIED);
}

ECode AS::IsAutoCommit(
    UInt32 uAddr,
    Boolean *pIsAutoCommit)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uAddr, pSeg->m_uBase, pSeg->m_uSize)) {
            *pIsAutoCommit = pSeg->IsAutoCommit();
            AS_EXIT(NOERROR);
        }
    }

    AS_EXIT(E_ACCESS_DENIED);
}

Boolean AS::IsValidAddress(const UInt32 uAddr)
{
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uAddr, pSeg->m_uBase, pSeg->m_uSize)) {

            AS_EXIT(TRUE);
        }
    }

    if (FALL_INTO((UInt32)uAddr, (UInt32)PROXY_ENTRY_BASE, (UInt32)PAGE_SIZE)
        || FALL_INTO((UInt32)uAddr,
        (UInt32)USER_BLOCK_BASE, (UInt32)USER_BLOCK_SIZE)) {

        AS_EXIT(TRUE);
    }

    AS_EXIT(FALSE);
}

ECode AS::Hit(UInt32 uAddr)
{
    ECode ec;
    DLinkNode *pCurrentList;
    VSegment *pSeg;

    assert(m_pHat && "AS has not been initialized");

    if (uAddr < COMMON_LIMIT) {
        pCurrentList = &m_commList;
    }
    else {
        pCurrentList = &m_privList;
    }

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, pCurrentList) {
        if (FALL_INTO(uAddr, pSeg->m_uBase, pSeg->m_uSize)) {
            ec = pSeg->Hit(uAddr);

            AS_EXIT(ec);
        }
    }

    AS_EXIT(E_DOES_NOT_EXIST);
}

ECode AS::Break(UInt32 uAddr)
{
    ECode ec;

    assert(m_pHat && "AS has not been initialized");
    assert(PAGE_OFFSET(uAddr) == 0);

    if (uAddr < USER_HEAP_BASE || uAddr > USER_HEAP_LIMIT) {
        return E_INVALID_ARGUMENT;
    }

    AS_ENTER();

    if (!m_pHeapSeg) {
        //
        // Heap segment has not been created, try to create new one.
        //

        if (!m_privList.IsEmpty()
            && uAddr > ((VSegment *)m_privList.First())->m_uBase) {
            AS_EXIT(E_NOT_ENOUGH_ADDRESS_SPACE);
        }
        if (g_UserHeapGrowThreshold > (Int32)(GetNumberOfFreePages() \
                - B_TO_P(uAddr - USER_HEAP_BASE))) {
            kputs("\n-------------------------------------------");
            kputs("\n>>>> *ERROR* Not enough memory for as break");
            kputs("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
            if (g_UserHeapGrowThreshold == g_HeapGrow1stThreshold) {
                g_UserHeapGrowThreshold = g_HeapGrow2ndThreshold;
                kputs("\n--------------------------------------------------");
                kputs("\n>>>> *NOTE* Set user heap grow threshold to"
                        " 2nd threshold");
                kputs("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
            }
            AS_EXIT(E_OUT_OF_MEMORY);
        }

        m_pHeapSeg = new StdSegment(
            this,
            USER_HEAP_BASE,
            uAddr - USER_HEAP_BASE,
            MemoryMap_Fixed | MemoryMap_Private | MemoryMap_UpGrow,
            MemoryProtection_RW,
            NULL,
            0);
        if (!m_pHeapSeg) AS_EXIT(E_OUT_OF_MEMORY);

        if ((ec = m_pHeapSeg->InitMap()) != NOERROR) {
            delete m_pHeapSeg;
            m_pHeapSeg = NULL;
            AS_EXIT(ec);
        }
        if ((ec = m_pHeapSeg->Hit(uAddr - 1)) != NOERROR) {
            delete m_pHeapSeg;
            m_pHeapSeg = NULL;
            AS_EXIT(ec);
        }
        m_privList.InsertFirst(m_pHeapSeg);
        AS_EXIT(NOERROR);
    }
    else if ((m_pHeapSeg->m_pNext == &m_privList)
        || (((VSegment*)m_pHeapSeg->m_pNext)->m_uBase >= uAddr)) {
        UInt32 uSize = uAddr - USER_HEAP_BASE;

        if (uSize > m_pHeapSeg->m_uSize) {
            if (g_UserHeapGrowThreshold > (Int32)(GetNumberOfFreePages() \
                    - B_TO_P(uSize - m_pHeapSeg->m_uSize))) {
                kputs("\n-------------------------------------------");
                kputs("\n>>>> *ERROR* Not enough memory for as break");
                kputs("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
                if (g_UserHeapGrowThreshold == g_HeapGrow1stThreshold) {
                    g_UserHeapGrowThreshold = g_HeapGrow2ndThreshold;
                    kputs("\n-----------------------------------------------");
                    kputs("\n>>>> *NOTE* Set user heap grow threshold to"
                                " 2nd threshold");
                    kputs("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
                }
                AS_EXIT(E_OUT_OF_MEMORY);
            }
            m_pHeapSeg->m_uSize = uSize;
            ec = m_pHeapSeg->Hit(uAddr -1);
            AS_EXIT(ec);
        }
        else if (uSize < m_pHeapSeg->m_uSize) {
            ec = m_pHeapSeg->Decrease(uAddr);
            AS_EXIT(ec);
        }
    }

    AS_EXIT(E_NOT_ENOUGH_ADDRESS_SPACE);
}

ECode AS::GetMemorySizes(
    Int32 * pPrivateVirtualMemorySize,
    Int32 * pSharedVirtualMemorySize,
    Int32 * pPrivatePhysicalMemorySize,
    Int32 * pSharedPhysicalMemorySize)
{
    AS_ENTER();

    register VSegment *pSeg;
    register uint_t uVMemSize;
    register uint_t uPMemSize;

    if (NULL != pPrivateVirtualMemorySize
        || NULL != pPrivatePhysicalMemorySize) {
        uVMemSize = USER_BLOCK_SIZE;
        uPMemSize = USER_BLOCK_SIZE;

        ForEachDLinkNode(VSegment *, pSeg, &m_privList) {
            uVMemSize += pSeg->m_uSize;

            if (NULL != pPrivatePhysicalMemorySize) {
                uPMemSize += pSeg->GetPhyscialMemorySize();
            }
        }

        if (NULL != pPrivateVirtualMemorySize) {
            *pPrivateVirtualMemorySize = (Int32)uVMemSize;
        }

        if (NULL != pPrivatePhysicalMemorySize) {
            *pPrivatePhysicalMemorySize = (Int32)uPMemSize;
        }
    }

    if (NULL != pSharedVirtualMemorySize
        || NULL != pSharedPhysicalMemorySize) {
        uVMemSize = 0;
        uPMemSize = 0;

        ForEachDLinkNode(VSegment *, pSeg, &m_commList) {
            uVMemSize += pSeg->m_uSize;

            if (NULL != pSharedPhysicalMemorySize) {
                uPMemSize += pSeg->GetPhyscialMemorySize();
            }
        }

        if (NULL != pSharedVirtualMemorySize) {
            *pSharedVirtualMemorySize = (Int32)uVMemSize;
        }

        if (NULL != pSharedPhysicalMemorySize) {
            *pSharedPhysicalMemorySize = (Int32)uPMemSize;
        }
    }

    AS_EXIT(NOERROR);
}

#ifndef _RELEASE

#include <util/kprint.h>

void AS::View()
{
    VSegment *pSeg;

    kprintf("---- CommonAs VIEW ----\n");
    kprintf("  BASE        SIZE        LIMIT\n");

    AS_ENTER();

    ForEachDLinkNode(VSegment *, pSeg, &m_commList) {
        kprintf("%08x    %08x    %08x\n",
                pSeg->m_uBase, pSeg->m_uSize, pSeg->m_uBase + pSeg->m_uSize);
    }
    kprintf("\n");

    kprintf("---- PrivateAS VIEW ----\n");
    kprintf("  BASE        SIZE        LIMIT\n");
    ForEachDLinkNode(VSegment *, pSeg, &m_privList) {
        kprintf("%08x    %08x    %08x\n",
                pSeg->m_uBase, pSeg->m_uSize, pSeg->m_uBase + pSeg->m_uSize);
    }
    kprintf("\n");

    AS_EXIT(;);
}

#endif // _RELEASE
